package com.songlanyun.modules.marketing.groupbuy.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.songlanyun.common.config.SemaphoreTool;
import com.songlanyun.common.enums.MarketingConstant;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.BeanUtil;
import com.songlanyun.common.utils.RedisUtils;
import com.songlanyun.modules.exception.MarketingException;
import com.songlanyun.modules.exception.OrderException;
import com.songlanyun.modules.goods.entity.Goods;
import com.songlanyun.modules.goods.entity.GoodsSku;
import com.songlanyun.modules.goods.service.GoodsService;
import com.songlanyun.modules.goods.service.GoodsSkuService;
import com.songlanyun.modules.marketing.groupbuy.entity.GroupBuyActivity;
import com.songlanyun.modules.marketing.groupbuy.entity.GroupBuyGoodsSku;
import com.songlanyun.modules.marketing.groupbuy.model.dto.GroupBuyActivityGoodsDTO;
import com.songlanyun.modules.marketing.groupbuy.model.vo.GroupBuyActivityGoodsVO;
import com.songlanyun.modules.marketing.groupbuy.model.vo.GroupBuyActivityVO;
import com.songlanyun.modules.marketing.groupbuy.service.GroupBuyActivityService;
import com.songlanyun.modules.marketing.groupbuy.service.GroupBuyGoodsSkuService;
import com.songlanyun.modules.marketing.seckill.entity.SeckillActivityGoods;
import com.songlanyun.modules.marketing.seckill.entity.SeckillGoodsSku;
import com.songlanyun.modules.marketing.seckill.model.vo.SeckillActivityGoodsVO;
import com.songlanyun.modules.marketing.seckill.service.SeckillActivityGoodsService;
import com.songlanyun.modules.singlegoods.entity.ProductSingleGoodsEntity;
import com.songlanyun.modules.singlegoods.service.ProductSingleGoodsService;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RSemaphore;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.utils.PageUtils;
import com.songlanyun.common.utils.Query;

import com.songlanyun.modules.marketing.groupbuy.dao.GroupBuyActivityGoodsDao;
import com.songlanyun.modules.marketing.groupbuy.entity.GroupBuyActivityGoods;
import com.songlanyun.modules.marketing.groupbuy.service.GroupBuyActivityGoodsService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;


@Service("groupBuyActivityGoodsService")
public class GroupBuyActivityGoodsServiceImpl extends ServiceImpl<GroupBuyActivityGoodsDao, GroupBuyActivityGoods> implements GroupBuyActivityGoodsService {

    @Resource
    private GroupBuyGoodsSkuService groupBuyGoodsSkuService;

    @Resource
    private GroupBuyActivityService groupBuyActivityService;

    @Resource
    private GoodsService goodsService;

    @Resource
    private GoodsSkuService goodsSkuService;

    @Resource
    private SemaphoreTool semaphoreTool;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private ProductSingleGoodsService productSingleGoodsService;

    @Override
    public PageUtils goodsPage(Map<String, Object> params) {
        IPage<GroupBuyActivityGoodsVO> page = this.baseMapper.goodsPage(
                new Query<GroupBuyActivityGoodsVO>().getPage(params), params);

        return new PageUtils(page);
    }

    /**
     * 保存拼团活动商品
     *
     * @param dto
     */
    @Override
    @Transactional
    public void saveGoods(GroupBuyActivityGoodsDTO dto) {

        //1、保存拼团活动
        //1.1如果该拼团活动是否已经有该商品,有则是修改，没有保存
        GroupBuyActivityGoods groupBuyGoods = this.getByGoodsIdAndGroupBuyId(dto.getGoodsId(), dto.getGroupBuyId());
        if (groupBuyGoods == null) {
            groupBuyGoods = new GroupBuyActivityGoods();
        }
        BeanUtil.copyPropertiesIgnoreNull(dto, groupBuyGoods);//拷贝
        groupBuyGoods.setPriceType(MarketingConstant.PriceType.getByCode(dto.getPriceType()));//活动打折方式
        //保存商品的规格
        Goods goods = goodsService.getById(groupBuyGoods.getGoodsId(), true);
        groupBuyGoods.setShopId(goods.getShopId());//发布商家
        groupBuyGoods.setSkuTableValue(goods.getSkuTableValue());

        //可售数量+初始化销量>=已售数量
        if ((groupBuyGoods.getRealStockTotal() + groupBuyGoods.getInitSaleNum()) < groupBuyGoods.getResultSaleNum()) {
            throw new RRException(MarketingException.SALE_EXCEPTION);
        }

        //1.2保存或更新
        this.saveOrUpdate(groupBuyGoods);

        //2、保存拼团活动sku
        //2.1查询拼团活动商品sku是否有记录
        Long groupBuyGoodsId = groupBuyGoods.getId();
        //2.2有则先删除记录
        groupBuyGoodsSkuService.deleteByGroupBuyGoodsId(groupBuyGoodsId);
        //2.3 批量
        List<GroupBuyGoodsSku> groupBuyGoodsSkuList = dto.getGroupBuyGoodsSkuList();
        List<GroupBuyGoodsSku> removeSkuList = new ArrayList<>();
        for (GroupBuyGoodsSku g : groupBuyGoodsSkuList) {
            //查询商品sku
            GoodsSku goodsSku = goodsSkuService.loadByGoodsAndSkuHashCode(dto.getGoodsId(), g.getSkuHashCode());
            if (goodsSku == null) {
                //万一商品sku未找到,则不添加，跳过，防止报错
                removeSkuList.add(g);
                continue;
            }
            BeanUtil.copyPropertiesIgnoreNull(goodsSku, g);
            if (g.getActivityPrice().compareTo(goodsSku.getSalePrice()) > 0) {
                //拼团活动商品的活动价不能大于商品销售价
                throw new RRException(MarketingException.GROUP_BUY_ACTIVITY_GOODS_PRICE_ERROR);
            }

            if(g.getActivityPrice().compareTo(BigDecimal.ZERO)<=0)
            {
                throw new RRException("活动价格不能小于等于0");
            }

            //重置id
            g.setId(null);
            g.setGroupBuyGoodsId(groupBuyGoodsId);
        }

        //删除不存在的sku
        groupBuyGoodsSkuList.removeAll(removeSkuList);
        if(CollectionUtil.isEmpty(groupBuyGoodsSkuList))
        {
            throw new RRException(MarketingException.GROUP_BUY_ACTIVITY_GOODS_SKU_ERROR);
        }
        //批量
        groupBuyGoodsSkuService.saveBatch(groupBuyGoodsSkuList);

        //3、更新拼团活动
        //3.1计算最大、最小价格
        //最小价格
        BigDecimal minPrice = groupBuyGoodsSkuList.stream().map(GroupBuyGoodsSku::getActivityPrice).min(BigDecimal::compareTo).orElseGet(() -> BigDecimal.ZERO);
        //最大价格
        BigDecimal maxPrice = groupBuyGoodsSkuList.stream().map(GroupBuyGoodsSku::getActivityPrice).max(BigDecimal::compareTo).orElseGet(() -> BigDecimal.ZERO);
        groupBuyGoods.setMinPrice(minPrice);
        groupBuyGoods.setMaxPrice(maxPrice);

        groupBuyGoods.setMinSalePrice(goods.getMinSalePrice());//最小销售价
        groupBuyGoods.setMaxSalePrice(goods.getMaxSalePrice());//最大销售价
        //3.2计算销量和库存
        groupBuyGoods.computeResultSaleAndResidueStock();
        this.baseMapper.updateById(groupBuyGoods);

        //创建信号量
        createAndSetSemaphore(groupBuyGoods);

    }

    @Override
    public GroupBuyActivityGoods getByGoodsIdAndGroupBuyId(Long goodsId, Long groupBuyId) {
        GroupBuyActivityGoods groupBuyActivityGoods = this.baseMapper.selectOne(
                new LambdaQueryWrapper<GroupBuyActivityGoods>()
                        .eq(GroupBuyActivityGoods::getGoodsId, goodsId)
                        .eq(GroupBuyActivityGoods::getGroupBuyId, groupBuyId)
                        .last("limit 1")
        );

        return groupBuyActivityGoods;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) {

        GroupBuyActivityGoods goods = this.loadActivityGoodsById(id, true);
        GroupBuyActivity activity = groupBuyActivityService.getById(goods.getGroupBuyId());
//        //拼团活动开始了，就不能被删除
//        if (System.currentTimeMillis() >= activity.getStartTime().getTime()) {
//            throw new RRException(MarketingException.GROUP_BUY_ACTIVITY_GOODS__NOT_DEL);
//        }
        //拼团活动在进行中了，就不能被删除
        if (MarketingConstant.ActiveState.UNDERWAY == activity.getActiveState()) {
            throw new RRException(MarketingException.GROUP_BUY_ACTIVITY_GOODS__NOT_DEL);
        }

        //1、删除拼团活动商品
        this.baseMapper.deleteById(id);

        //2、删除拼团活动商品sku
        groupBuyGoodsSkuService.deleteByGroupBuyGoodsId(id);

        //删除拼团的信号量
        redisUtils.delete(GroupBuyActivityGoodsService.getSemaphoreKey(goods.getGroupBuyId(), goods.getId(), goods.getGoodsId()));

    }


    @Override
    public GroupBuyActivityGoods getGoodsAndSkuById(Long id) {
        GroupBuyActivityGoods goods = this.baseMapper.selectById(id);
        if (goods != null) {
            List<GroupBuyGoodsSku> skuList = groupBuyGoodsSkuService.getByGroupBuyGoodsId(goods.getId());
            goods.setGroupBuyGoodsSkuList(skuList);
        }
        return goods;
    }

    @Override
    public GroupBuyActivityGoods loadActivityGoodsById(Long id, Boolean tw) {
        GroupBuyActivityGoods goods = this.baseMapper.selectById(id);
        if (goods == null && tw) {
            throw new RRException(MarketingException.GROUP_BUY_ACTIVITY_GOODS_NOT_EXIST);
        }
        return goods;
    }

    @Override
    public GroupBuyActivityVO groupBuying(Long shopId) {
        //查询正在拼团的商品
        List<GroupBuyActivityGoodsVO> list = this.baseMapper.groupBuying(shopId);
        GroupBuyActivityVO vo = new GroupBuyActivityVO();
        vo.setGroupBuyActivityGoodsList(list);

        if (list != null && list.size() > 0) {
            //结束时间
            Long time = groupBuyActivityService.finishTime(shopId);
            vo.setFinishTime(time);

            list.forEach(GroupBuyActivityGoodsVO::loadDiscount);
        }


        return vo;
    }

    @Override
    public GroupBuyActivityGoodsVO getGoodsInfo(Long id, Boolean isThrow) {
        Map<String, Object> params = new HashMap<>();
        params.put("group_buy_goods_id", id);
        GroupBuyActivityGoodsVO vo = this.baseMapper.groupBuyGoodsInfo(params);
        if (vo == null) {
            if (isThrow) {
                throw new RRException(MarketingException.GROUP_BUY_ACTIVITY_GOODS_NOT_EXIST);
            }

        } else {
            vo.loadDiscount();
        }

        return vo;
    }

    /**
     * 获得销量
     *
     * @param activityGoodsId
     * @return
     */
    @Override
    public Integer getStock(Long activityGoodsId) {
        GroupBuyActivityGoods groupBuyActivityGoods = this.loadActivityGoodsById(activityGoodsId, true);
        return groupBuyActivityGoods.getResidueStockTotal();
    }

    /**
     * 判断当前时间段有没有指定拼团活动的商品存在
     *
     * @param groupBuyId 拼团活动id
     * @param goodsId    商品id
     * @return
     */
    @Override
    public Boolean verifyByGroupBuyAndGoods(Long groupBuyId, Long goodsId) {
        return this.baseMapper.verifyByGroupBuyAndGoods(groupBuyId, goodsId);
    }

    /**
     * 判断当前时间段有没有指定拼团活动商品存在
     *
     * @param groupBuyGoodsId 拼团活动商品id
     * @return
     */
    @Override
    public Boolean verifyByGroupBuyGoods(Long groupBuyGoodsId) {
        return this.baseMapper.verifyByGroupBuyGoods(groupBuyGoodsId);
    }

    @Override
    public List<GroupBuyActivityGoods> getGoodsListBuyGroupBuyId(Long groupBuyId) {

        return this.baseMapper.listByGroupBuyId(groupBuyId);
    }


    /**
     * 创建信号量并设置容量
     *
     * @param goods 秒杀商品
     * @return
     */
    @Override
    public void createAndSetSemaphore(GroupBuyActivityGoods goods) {

        String key = GroupBuyActivityGoodsService.getSemaphoreKey(goods.getGroupBuyId(), goods.getId(), goods.getGoodsId());
        Integer num = redisUtils.get(key, Integer.class);
        if (num != null) {
            redisUtils.delete(key);
        }
        semaphoreTool.setRSemaphorePermits(key, goods.getResidueStockTotal());
    }


    /**
     * 获取当前的信号
     *
     * @param goods
     * @return
     */
    @Override
    public RSemaphore getSemaphore(GroupBuyActivityGoods goods) {
        return semaphoreTool.getRSemaphore(GroupBuyActivityGoodsService.getSemaphoreKey(goods.getGroupBuyId(), goods.getId(), goods.getGoodsId()));
    }

    /**
     * 获取信号量，如果获取成功信号号会减少
     *
     * @param activityId
     * @param activityGoodsId
     * @param goodsId
     * @param size
     * @return
     */
    @Override
    public Boolean tryAcquire(Long activityId, Long activityGoodsId, Long goodsId, int size) {
        return semaphoreTool.tryAcquire(GroupBuyActivityGoodsService.getSemaphoreKey(activityId, activityGoodsId, goodsId), size);
    }


    /**
     * 释放（回退）信号量,
     *
     * @param goods
     * @param size
     */
    @Override
    public void release(GroupBuyActivityGoods goods, int size) {
        semaphoreTool.release(GroupBuyActivityGoodsService.getSemaphoreKey(goods.getGroupBuyId(), goods.getId(), goods.getGoodsId()), size);
    }


    /**
     * 释放（回退）信号量,
     *
     * @param activityId
     * @param activityGoodsId
     * @param goodsId
     * @param size
     */
    @Override
    public void release(Long activityId, Long activityGoodsId, Long goodsId, int size) {
        semaphoreTool.release(GroupBuyActivityGoodsService.getSemaphoreKey(activityId, activityGoodsId, goodsId), size);

    }

    @Override
    public List<GroupBuyGoodsSku> getSkusById(Long groupBuyGoodsId) {
        GroupBuyActivityGoods goods = this.baseMapper.selectById(groupBuyGoodsId);
        //查询sku
        List<GroupBuyGoodsSku> skus = groupBuyGoodsSkuService.getByGroupBuyGoodsId(groupBuyGoodsId);

        skus.forEach(s -> {
            ProductSingleGoodsEntity singleGoods = productSingleGoodsService.getByShopIdAndId(goods.getShopId(), s.getSingleGoodsId());
            Integer ableStock = 0;
            if (singleGoods != null) {
                //库存
                ableStock = singleGoods.getAbleStock();
            }
            s.setAbleStock(ableStock);

        });
        return skus;
    }

    @Override
    public List<GroupBuyActivityGoodsVO> willYouSpell(Map<String, Object> params) {
        return this.baseMapper.willYouSpell(params);
    }

    @Override
    public PageUtils willYouSpellPage(Map<String, Object> params) {
        IPage<GroupBuyActivityGoodsVO> page = this.baseMapper.willYouSpellPage(new Query<GroupBuyActivityGoodsVO>().getPage(params), params);
        return new PageUtils(page);
    }

    @Override
    public void verifyActiveGoods(Long groupBuyId) {
        Integer count = this.baseMapper.selectCount(
                new LambdaQueryWrapper<GroupBuyActivityGoods>()
                        .eq(GroupBuyActivityGoods::getGroupBuyId, groupBuyId)
        );

        if (count > 0) {
            throw new RRException(MarketingException.GROUP_BUY_ACTIVITY_GOODS_EXIST);
        }
    }

    @Override
    public List<GroupBuyActivityGoodsVO> groupBuyingGoodsList(Long shopId) {
        return this.baseMapper.groupBuying(shopId);
    }
}
